import { VERSION, JMOptions, LayoutOptions, ViewOptions, NodeTreeFormatMeta, NodeArrayFormatMeta } from './models'
import { DataProvider } from './DataProvider'
import { LayoutProvider } from './LayoutProvider'
import { ViewProvider } from './ViewProvider'
import { ShorcutProvider } from './ShorcutProvider'
import * as MGUtils from './utils'
import { Mind } from './Mind'
import { Node } from './Node'

export class MindGraph {
    // 默认参数
    options: JMOptions = {
        container : '',   // id of the container
        editable : false, // you can change it in your options
        theme : null,
        mode :'full',     // full or side
        support_html : true,
        view:{
            hmargin:100,
            vmargin:50,
            line_width:2,
            line_color:'#555'
        },
        layout:{
            hspace:30,
            vspace:20,
            pspace:13
        },
        default_event_handle:{
            enable_mousedown_handle:true,
            enable_click_handle:true,
            enable_dblclick_handle:true
        },
        shortcut:{
            enable:true,
            handles:{
            },
            mapping:{
                addchild   : 45, // Insert
                addbrother : 13, // Enter
                editnode   : 113,// F2
                delnode    : 46, // Delete
                toggle     : 32, // Space
                left       : 37, // Left
                up         : 38, // Up
                right      : 39, // Right
                down       : 40, // Down
            }
        }
    }

    inited: boolean = false
    // Mind 对象
    mind: Mind = null
    // DataProvider 对象
    data: DataProvider = null
    // LayoutProvider 对象
    layout: LayoutProvider = null
    // ViewProvider 对象
    view: ViewProvider = null
    // ShorcutProvider 对象
    shortcut: ShorcutProvider = null
    eventHandles: any[] = []

    version = null
    // 当有多个思维导图时用
    static current: MindGraph = null

    constructor(opts: JMOptions) {
        MindGraph.current = this
        this.version = VERSION
        // 整合配置项
        MGUtils.JsonUtils.merge(this.options, opts)

        // 如果container为空返回报错
        if (!opts.container) {
            console.error('the options.container should not be null or empty.');
            return;
        }
        this.inited = false
        this.mind = null
        this.eventHandles = []
        this.init()
    }

    /**
     * 初始化函数
     */
    init () {
        if(this.inited){return;}
        this.inited = true;

        var opts = this.options;

        var opts_layout: LayoutOptions = {
            mode:opts.mode,
            hspace:opts.layout.hspace,
            vspace:opts.layout.vspace,
            pspace:opts.layout.pspace
        }
        var opts_view: ViewOptions = {
            container:opts.container,
            support_html:opts.support_html,
            hmargin:opts.view.hmargin,
            vmargin:opts.view.vmargin,
            line_width:opts.view.line_width,
            line_color:opts.view.line_color
        };
        // create instance of function provider
        this.data = new DataProvider(this);
        this.layout = new LayoutProvider(this, opts_layout);
        this.view = new ViewProvider(this, opts_view);
        this.shortcut = new ShorcutProvider(this, opts.shortcut);

        this.data.init();
        this.layout.init();
        this.view.init();
        this.shortcut.init();

        this._event_bind();

        MindGraph.init_plugins(this);
    }

    show(mind?: NodeTreeFormatMeta | NodeArrayFormatMeta) {
        this._reset()
        this._show(mind)
    }

    /**
     * 绑定鼠标 按下、点击、双击事件，分别对应 选中、扩展器、编辑 相关的操作
     */
    private _event_bind() {
        this.view.addEvent(this, 'mousedown', this.mousedownHandle)
        this.view.addEvent(this, 'click', this.clickHandle)
        this.view.addEvent(this, 'dblclick', this.dblClickHandle)
    }

    /**
     * 初始化插件 TODO:
     * @param mindGraph 
     */
    static init_plugins(mindGraph: MindGraph) {

    }

    /**
     * 根据 id 更新 显示内容 TODO:
     * @param nodeid 
     * @param topic 
     */
    updateNode (nodeid: string, topic: string) {

    }

    /**
     * 根据 id 返回 Node 节点 TODO:
     * @param nodeid 
     */
    getNode(nodeid: string):Node {
        return null
    }

    /**
     * 当 <jsnodes> 鼠标按下，如果是节点，则选中，如果不是，则清除所有选中
     */
    mousedownHandle (e) {
        if (!this.options.default_event_handle['enable_mousedown_handle']) {
            return;
        }
        var element = e.target || event.srcElement;
        var nodeid = this.view.getBindedNodeId(element);
        if(!!nodeid){ // 如果 nodeid 存在
            this.selectNode(nodeid);
        }else{
            this.selectClear();
        }
    }
    /**
     * 当 <jsnodes> 鼠标单击， 如果是 扩展器，则 负责切换子节点的显示与隐藏
     */
    clickHandle (e) {
        if (!this.options.default_event_handle['enable_click_handle']) {
            return;
        }
        var element = e.target || event.srcElement;
        var isexpander = this.view.isExpander(element);
        if(isexpander){
            var nodeid = this.view.getBindedNodeId(element);
            if(!!nodeid){
                this.toggleNode(nodeid);
            }
        }
    }
    /**
     * 当 <jsnodes> 鼠标双击，把 输入框定位至 节点位置
     */
    dblClickHandle (e) {
        if (!this.options.default_event_handle['enable_dblclick_handle']) {
            return;
        }
        if(this.getEditable()){
            var element = e.target || event.srcElement;
            // 根据 element 获取节点 id
            var nodeid = this.view.getBindedNodeId(element);
            if(!!nodeid){
                this.beginEdit(nodeid);
            }
        }
    }

    /**
     * 根据 nodeid，设置选中
     * @param nodeid 
     */
    selectNode (nodeid: string | Node) {
        if(!MGUtils.CommonUtils.isNode(nodeid as string)){
            var the_node = this.getNode(nodeid as string);
            if(!the_node){
                console.error('the node[id='+nodeid+'] can not be found.');
                return;
            }else{
                return this.selectNode(the_node);
            }
        }
        if(!this.layout.isVisible(nodeid as Node)){
            return;
        }
        this.mind.selected = nodeid as Node;
        this.view.selectNode(nodeid as Node);
    }

    /**
     * 清除选中
     */
    selectClear() {
        if(!!this.mind){
            this.mind.selected = null;
            this.view.selectClear();
        }
    }

    /**
     * 设置子节点树的展开与收起
     * @param node 
     */
    toggleNode(node: string | Node) {
        if(!MGUtils.CommonUtils.isNode(node)){
            var the_node = this.getNode(node as string);
            if(!the_node){
                console.error('the node[id='+node+'] can not be found.');
                return;
            }else{
                return this.toggleNode(the_node);
            }
        }
        if((node as Node).isroot){return;}
        this.view.saveLocation(node as Node);
        // 重新计算布局
        this.layout.toggleNode(node as Node);
        // view TODO: 过程未读
        this.view.relayout();
        // TODO: 过程未读
        this.view.restoreLocation(node as Node);
    }

    /**
     * 是否已经配置 editable 项
     */
    getEditable (): boolean {
        return this.options.editable
    }

    /**
     * 开始在 node 节点处编辑 TODO:
     * @param node 
     */
    beginEdit(node: string | Node) {

    }

    private _reset() {
        this.view.reset();
        this.layout.reset();
        this.data.reset();
    }

    private _show(mind: NodeArrayFormatMeta | NodeTreeFormatMeta) {
        var m = mind || NodeArrayFormat.example;

        this.mind = this.data.load(m);
        if(!this.mind){
            logger.error('data.load error');
            return;
        }else{
            logger.debug('data.load ok');
        }

        this.view.load();
        logger.debug('view.load ok');

        this.layout.layout();
        logger.debug('layout.layout ok');

        this.view.show(true);
        logger.debug('view.show ok');

        this.invoke_event_handle(jm.event_type.show,{data:[mind]});
    }
}